// 电源指示灯程序，用于控制电源指示灯的亮灭
#include <thread>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

//第三方库
#include <curl/curl.h>

#include "gpio_control.h"


void locke_delay_ms(unsigned int t){
    std::this_thread::sleep_for(std::chrono::milliseconds(t));
}

//ping操作的测试
bool canCommunicateWithIP(const std::string &ip) {
    // 创建原始套接字
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("socket");
        return false;
    }

    // 设置目标IP地址和ICMP包的类型、标识符和序列号
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip.c_str());

    struct icmp icmp;
    memset(&icmp, 0, sizeof(icmp));
    icmp.icmp_type = ICMP_ECHO;
    icmp.icmp_id = getpid() & 0xffff;
    icmp.icmp_seq = 1;
    icmp.icmp_cksum = 0;
    icmp.icmp_cksum = htons(~(ICMP_ECHO << 8));

    // 发送ICMP包到目标IP地址
    int ret = sendto(sockfd, &icmp, sizeof(icmp), 0, (struct sockaddr*)&addr, sizeof(addr));
    if (ret < 0) {
        perror("sendto");
        close(sockfd);
        return false;
    }

    // 关闭套接字
    close(sockfd);

    return true;
}

static size_t write_temp(void *contents, size_t size, size_t nmemb, void *userp) {
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

//http协议 获取数据
int is_get_info(const char* url){
    CURL *curl;
    CURLcode res;
    std::string temp;

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_temp);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &temp);
        res = curl_easy_perform(curl);
        if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();

    //判断数据是否有效
    //printf(">>>data: %s \n\r",temp.c_str());
    if(temp.empty()){
        //为空
        return 0;
    }else{
        //不为空
        return 1;
    }

}


//led状态获取
int led_state(unsigned int *a,unsigned int *b){
    //这里用来监控设备的状态的
    int enable_mode=0;

    //确认10.222.222.102 ping通讯是否正常？
    if (canCommunicateWithIP("10.222.222.102"))
    {
        //连接正常
        enable_mode=0;
        //检测是否可以获得102上的数据
        if (is_get_info("http://10.222.222.102/get_info") == 0)
        {
            //也获取不到102数据
            enable_mode=2;
        }
    }else{
        //无法连接102
        enable_mode=1;
    }

    // 设置亮灭时间
    switch (enable_mode)
    {
    case 0:         //正常运行的
        *a=1000;*b=1000;
        break;
    case 1:         //ping不通102
        *a=100;*b=100;
        break;
    case 2:         //网络通，但是获取不到102数据
        /* code */
        *a=1000;*b=100;
        break;
    case 3:         // 其他
        /* code */
        *a=100;*b=1000;
        break;
    
    default:
        *a=1000;*b=0;   //  常亮
        break;
    }

    sleep(1);//间隔时间
    
}

//led 显示
void led_show(gpio_control led_dev,unsigned int *a,unsigned int *b){
    //跑到天荒地老
    
    //这里只要是实现显示部分
    while (1)
    {
        /* code */
        led_dev.gpio_outvalue(1);
        locke_delay_ms((*a));
        led_dev.gpio_outvalue(0);
        locke_delay_ms((*b));
    }
    
}


int main(){

    std::cout <<"电源指示灯程序~~~"<< std::endl;

    int led_pin = 106;

    //时间参数（单位：毫秒）
    unsigned int h_time=1000;//灯亮的时间
    unsigned int l_time=100;//灯灭的时间
    unsigned int s_time=h_time+l_time;//周期时间

    //初始化引脚
    gpio_control led = gpio_control(led_pin);
    led.gpio_direction("out");
    led.gpio_outvalue(1);

    // 创建led显示线程
    std::thread led_show_th(led_show,led,&h_time,&l_time);
    
    while (1)
    {
        /* code */
        led_state(&h_time,&l_time);
        sleep(1);
    }
    

    return 0;
}





